﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Microsoft.International.Formatters
{
    /// <summary>
    /// Russian (ru-RU) Formatter
    /// </summary>
    [FormatCultureInfo("ru-RU")]
    internal sealed class RUStdFormatter : EuropeFormatter
    {
        /// <summary>
        /// Converts Decimal value to String representation
        /// </summary>
        /// <param name="num">Decimal to convert</param>
        /// <returns>String representation</returns>
        internal override string ConvertToLocalizedText(decimal num)
        {
            if (num == 0)
                return "Ноль";

            int n = (int)Math.Abs(num);
            int remainder = (int)((num - n) * 100);

            StringBuilder result = new StringBuilder();

            if (n == 0)
                result.Append("0 ");

            result.Append(NumberConverter.Convert(n, true, String.Empty, String.Empty, String.Empty));

            n /= 1000;
            result.Insert(0, NumberConverter.Convert(n, false, "тысяча", "тысячи", "тысяч"));

            n /= 1000;
            result.Insert(0, NumberConverter.Convert(n, true, "миллион", "миллиона", "миллионов"));

            n /= 1000;
            result.Insert(0, NumberConverter.Convert(n, true, "миллиард", "миллиарда", "миллиардов"));

            n /= 1000;
            result.Insert(0, NumberConverter.Convert(n, true, "триллион", "триллиона", "триллионов"));

            n /= 1000;
            result.Insert(0, NumberConverter.Convert(n, true, "триллиард", "триллиарда", "триллиардов"));
           
            return result.ToString();
        }

        /// <summary>
        /// This class does actual convert
        /// </summary>
        private class NumberConverter
        {
            private static List<string> hundreds = new List<string>() {"", "сто ", "двести ", "триста ", "четыреста ",
            "пятьсот ", "шестьсот ", "семьсот ", "восемьсот ", "девятьсот " };

            private static List<string> tens = new List<string>() {"", "десять ", "двадцать ", "тридцать ", "сорок ", "пятьдесят ",
            "шестьдесят ", "семьдесят ", "восемьдесят ", "девяносто "};

            /// <summary>
            /// Static method that converts integer number to string representation
            /// </summary>
            /// <param name="num">A number to convert</param>
            /// <param name="ismale">Gender that depending on segment (thousand etc.)</param>
            /// <param name="one">Level for one (e.g. "одна тысяча", "один миллион")</param>
            /// <param name="two">Level for two and above (e.g. "две тысячи", "два миллиона")</param>
            /// <param name="five">Level for five and above (e.g. "пять тысяч", "пфть миллионов")</param>
            /// <returns>String value for the segment</returns>
            public static string Convert(int num, bool ismale, string one, string two, string five)
            {
                List<string> list20 = new List<string>() {"", "один ", "два ", "три ", "четыре ", "пять ", "шесть ",
                "семь ", "восемь ", "девять ", "десять ", "одиннадцать ", "двенадцать ", "тринадцать ", "четырнадцать ", "пятнадцать ",
                "шестнадцать ", "семнадцать ", "восемнадцать ", "девятнадцать " };

                int intNum = (int)num % 1000;

                // Number should be above zero
                if (intNum < 0)
                    throw new ArgumentOutOfRangeException();
                else
                    if (intNum == 0)
                        return String.Empty;

                // list20 contains male strings by default. Replace first two in case if female
                if (!ismale)
                {
                    list20[1] = "одна ";
                    list20[2] = "две ";
                }

                // Buffer co collect result
                StringBuilder result = new StringBuilder(hundreds[intNum / 100]);

                if (intNum % 100 < 20)
                    result.Append(list20[intNum % 100]);
                else
                {
                    result.Append(tens[intNum % 100 / 10]);
                    result.Append(list20[intNum % 10]);
                }

                result.Append(Case(intNum, one, two, five));

                if (result.Length != 0) 
                    result.Append(" ");

                return result.ToString();
            }

            private static string Case(int num, string one, string two, string five)
            {
                switch ((num % 100 > 20) ? num % 10 : num % 20)
                {
                    case 1: 
                        return one;
                    case 2:
                    case 3:
                    case 4: 
                        return two;
                    default:
                        return five;
                }
            }
        }
    }
}
